/*
 * Copyright 2020 Google LLC
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#ifndef GrYUVABackendTextures_DEFINED
#define GrYUVABackendTextures_DEFINED

#include "include/core/SkYUVAInfo.h"
#include "include/gpu/GrBackendSurface.h"

#include <tuple>

/* *
 * A description of a set GrBackendTextures that hold the planar data described by a SkYUVAInfo.
 */
class SK_API GrYUVABackendTextureInfo {
public:
    static constexpr auto kMaxPlanes = SkYUVAInfo::kMaxPlanes;

    /* * Default GrYUVABackendTextureInfo is invalid. */
    GrYUVABackendTextureInfo() = default;

    /* *
     * Initializes a GrYUVABackendTextureInfo to describe a set of textures that can store the
     * planes indicated by the SkYUVAInfo. The texture dimensions are taken from the SkYUVAInfo's
     * plane dimensions. All the described textures share a common origin. The planar image this
     * describes will be mip mapped if all the textures are individually mip mapped as indicated
     * by skgpu::Mipmapped. This will produce an invalid result (return false from isValid()) if the
     * passed formats' channels don't agree with SkYUVAInfo.
     */
    GrYUVABackendTextureInfo(const SkYUVAInfo &, const GrBackendFormat[kMaxPlanes], skgpu::Mipmapped, GrSurfaceOrigin);

    GrYUVABackendTextureInfo(const GrYUVABackendTextureInfo &) = default;

    GrYUVABackendTextureInfo &operator = (const GrYUVABackendTextureInfo &) = default;

    bool operator == (const GrYUVABackendTextureInfo &) const;
    bool operator != (const GrYUVABackendTextureInfo &that) const
    {
        return !(*this == that);
    }

    const SkYUVAInfo &yuvaInfo() const
    {
        return fYUVAInfo;
    }

    SkYUVColorSpace yuvColorSpace() const
    {
        return fYUVAInfo.yuvColorSpace();
    }

    skgpu::Mipmapped mipmapped() const
    {
        return fMipmapped;
    }

    GrSurfaceOrigin textureOrigin() const
    {
        return fTextureOrigin;
    }

    /* * The number of SkPixmap planes, 0 if this GrYUVABackendTextureInfo is invalid. */
    int numPlanes() const
    {
        return fYUVAInfo.numPlanes();
    }

    /* * Format of the ith plane, or invalid format if i >= numPlanes() */
    const GrBackendFormat &planeFormat(int i) const
    {
        return fPlaneFormats[i];
    }

    /* *
     * Returns true if this has been configured with a valid SkYUVAInfo with compatible texture
     * formats.
     */
    bool isValid() const
    {
        return fYUVAInfo.isValid();
    }

    /* *
     * Computes a YUVALocations representation of the planar layout. The result is guaranteed to be
     * valid if this->isValid().
     */
    SkYUVAInfo::YUVALocations toYUVALocations() const;

private:
    SkYUVAInfo fYUVAInfo;
    GrBackendFormat fPlaneFormats[kMaxPlanes];
    skgpu::Mipmapped fMipmapped = skgpu::Mipmapped::kNo;
    GrSurfaceOrigin fTextureOrigin = kTopLeft_GrSurfaceOrigin;
};

/* *
 * A set of GrBackendTextures that hold the planar data for an image described a SkYUVAInfo.
 */
class SK_API GrYUVABackendTextures {
public:
    GrYUVABackendTextures() = default;
    GrYUVABackendTextures(const GrYUVABackendTextures &) = delete;
    GrYUVABackendTextures(GrYUVABackendTextures &&) = default;

    GrYUVABackendTextures &operator = (const GrYUVABackendTextures &) = delete;
    GrYUVABackendTextures &operator = (GrYUVABackendTextures &&) = default;

    GrYUVABackendTextures(const SkYUVAInfo &, const GrBackendTexture[SkYUVAInfo::kMaxPlanes],
        GrSurfaceOrigin textureOrigin);

    const std::array<GrBackendTexture, SkYUVAInfo::kMaxPlanes> &textures() const
    {
        return fTextures;
    }

    GrBackendTexture texture(int i) const
    {
        SkASSERT(i >= 0 && i < SkYUVAInfo::kMaxPlanes);
        return fTextures[static_cast<size_t>(i)];
    }

    const SkYUVAInfo &yuvaInfo() const
    {
        return fYUVAInfo;
    }

    int numPlanes() const
    {
        return fYUVAInfo.numPlanes();
    }

    GrSurfaceOrigin textureOrigin() const
    {
        return fTextureOrigin;
    }

    bool isValid() const
    {
        return fYUVAInfo.isValid();
    }

    /* *
     * Computes a YUVALocations representation of the planar layout. The result is guaranteed to be
     * valid if this->isValid().
     */
    SkYUVAInfo::YUVALocations toYUVALocations() const;

private:
    SkYUVAInfo fYUVAInfo;
    std::array<GrBackendTexture, SkYUVAInfo::kMaxPlanes> fTextures;
    GrSurfaceOrigin fTextureOrigin = kTopLeft_GrSurfaceOrigin;
};

#endif
